#include "stdafx.h"
#include "SoundClass.h"


CSoundClass::CSoundClass(void) : m_pDirectSound(nullptr), m_pPrimaryBuffer(nullptr), m_pSecondaryBuffer(nullptr)
{
}


CSoundClass::~CSoundClass(void)
{
}

bool CSoundClass::Initialize(HWND hWnd)
{
	bool bResult = false;

	bResult = InitializeDirectSound(hWnd);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to initialize direct sound");
		return false;
	}

	bResult = LoadWaveFile("../Resources/Sound/WantYouGone.wav", &m_pSecondaryBuffer);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to load wav file");
		return false;
	}

	//bResult = PlayWaveFile();
	//if(bResult == false)
	//{
	//	DEBUG_OUTPUT("Failed to play wav file");
	//	return false;
	//}

	return true;
}

void CSoundClass::ShutDown()
{
	ShutDownWaveFile(&m_pSecondaryBuffer);
	ShutDownDirectSound();
}

bool CSoundClass::InitializeDirectSound(HWND hWnd)
{
	HRESULT hResult;
	DSBUFFERDESC tBufferDesc;
	WAVEFORMATEX tWaveFormat;

	hResult = DirectSoundCreate8(NULL, &m_pDirectSound, NULL);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to create direct sound");
		return false;
	}

	hResult = m_pDirectSound->SetCooperativeLevel(hWnd, DSSCL_PRIORITY);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to set the sound coop level");
		return false;
	}

	tBufferDesc.dwSize = sizeof(DSBUFFERDESC);
	tBufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
	tBufferDesc.dwBufferBytes = 0;
	tBufferDesc.dwReserved = 0;
	tBufferDesc.lpwfxFormat = NULL;
	tBufferDesc.guid3DAlgorithm = GUID_NULL;

	hResult = m_pDirectSound->CreateSoundBuffer(&tBufferDesc, &m_pPrimaryBuffer, NULL);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to create primary sound buffer");
		return false;
	}

	tWaveFormat.wFormatTag = WAVE_FORMAT_PCM;
	tWaveFormat.nSamplesPerSec = 44100;
	tWaveFormat.wBitsPerSample = 16;
	tWaveFormat.nChannels = 2;
	tWaveFormat.nBlockAlign = (tWaveFormat.wBitsPerSample / 8) * tWaveFormat.nChannels;
	tWaveFormat.nAvgBytesPerSec = tWaveFormat.nSamplesPerSec * tWaveFormat.nBlockAlign;
	tWaveFormat.cbSize = 0;

	hResult = m_pPrimaryBuffer->SetFormat(&tWaveFormat);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to set sound format");
		return false;
	}

	return true;
}

void CSoundClass::ShutDownDirectSound()
{
	if(m_pPrimaryBuffer)
	{
		m_pPrimaryBuffer->Release();
		m_pPrimaryBuffer = nullptr;
	}

	if(m_pDirectSound)
	{
		m_pDirectSound->Release();
		m_pDirectSound = nullptr;
	}
}

bool CSoundClass::LoadWaveFile(char* cFileName, IDirectSoundBuffer8** pSecondaryBuffer)
{
	HRESULT hResult;
	FILE* pFilePtr;
	IDirectSoundBuffer* pTempBuffer;
	WaveHeaderType stWaveFileHeader;
	WAVEFORMATEX tWaveFormat;
	DSBUFFERDESC tBufferDesc;
	unsigned char* pWaveData;
	unsigned char* pBufferPtr;
	unsigned long unBufferSize;
	unsigned int unCount;
	int nError;

	nError = fopen_s(&pFilePtr, cFileName, "rb");
	if(nError != 0)
	{
		DEBUG_OUTPUT("Failed to open the wave file");
		return false;
	}

	unCount = fread(&stWaveFileHeader, sizeof(stWaveFileHeader), 1, pFilePtr);
	if(unCount != 1)
	{
		DEBUG_OUTPUT("Failed to read wave file header");
		return false;
	}

	if((stWaveFileHeader.cChunkID[0] != 'R') || (stWaveFileHeader.cChunkID[1] != 'I') || (stWaveFileHeader.cChunkID[2] != 'F') || (stWaveFileHeader.cChunkID[3] != 'F'))
	{
		DEBUG_OUTPUT("Wave header chunk id does not equal RIFF");
		return false;
	}

	if((stWaveFileHeader.cFormat[0] != 'W') || (stWaveFileHeader.cFormat[1] != 'A') || (stWaveFileHeader.cFormat[2] != 'V') || (stWaveFileHeader.cFormat[3] != 'E'))
	{
		DEBUG_OUTPUT("Wave header format does not equal WAVE");
		return false;
	}

	if((stWaveFileHeader.cSubChunkID[0] != 'f') || (stWaveFileHeader.cSubChunkID[1] != 'm') || (stWaveFileHeader.cSubChunkID[2] != 't') || (stWaveFileHeader.cSubChunkID[3] != ' '))
	{
		DEBUG_OUTPUT("Wave header sub chunk id does not equal fmt");
		return false;
	}

	if(stWaveFileHeader.usAudioFormat != WAVE_FORMAT_PCM)
	{
		DEBUG_OUTPUT("Wave header audio format does not equal WAVE_FORMAT_PCM");
		return false;
	}

	if(stWaveFileHeader.usNumChannels != 2)
	{
		DEBUG_OUTPUT("Wave header num channels does not equal 2");
		return false;
	}

	if(stWaveFileHeader.ulSampleRate != 44100)
	{
		DEBUG_OUTPUT("Wave header sample rate does not equal 44100");
		return false;
	}

	if(stWaveFileHeader.usBitsPerSample != 16)
	{
		DEBUG_OUTPUT("Wave header bits per sample does not equal 16");
		return false;
	}

	if((stWaveFileHeader.cDataChunkID[0] != 'd') || (stWaveFileHeader.cDataChunkID[1] != 'a') || (stWaveFileHeader.cDataChunkID[2] != 't') || (stWaveFileHeader.cDataChunkID[3] != 'a'))
	{
		DEBUG_OUTPUT("Wave header data chunk id does not equal data");
		return false;
	}

	tWaveFormat.wFormatTag = WAVE_FORMAT_PCM;
	tWaveFormat.nSamplesPerSec = 44100;
	tWaveFormat.wBitsPerSample = 16;
	tWaveFormat.nChannels = 2;
	tWaveFormat.nBlockAlign = (tWaveFormat.wBitsPerSample / 8) * tWaveFormat.nChannels;
	tWaveFormat.nAvgBytesPerSec = tWaveFormat.nSamplesPerSec * tWaveFormat.nBlockAlign;
	tWaveFormat.cbSize = 0;

	tBufferDesc.dwSize = sizeof(DSBUFFERDESC);
	tBufferDesc.dwFlags = DSBCAPS_CTRLVOLUME;
	tBufferDesc.dwBufferBytes = stWaveFileHeader.ulDataSize;
	tBufferDesc.dwReserved = 0;
	tBufferDesc.lpwfxFormat = &tWaveFormat;
	tBufferDesc.guid3DAlgorithm = GUID_NULL;

	hResult = m_pDirectSound->CreateSoundBuffer(&tBufferDesc, &pTempBuffer, NULL);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to create direct sound buffer");
		return false;
	}

	hResult = pTempBuffer->QueryInterface(IID_IDirectSoundBuffer8, (void**)&*pSecondaryBuffer);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to query direct sound interface");
		return false;
	}

	pTempBuffer->Release();
	pTempBuffer = nullptr;

	fseek(pFilePtr, sizeof(WaveHeaderType), SEEK_SET);

	pWaveData = new unsigned char[stWaveFileHeader.ulDataSize];
	if(pWaveData == nullptr)
	{		
		DEBUG_OUTPUT("Failed to create new wave data pointer");
		return false;
	}

	unCount = fread(pWaveData, 1, stWaveFileHeader.ulDataSize, pFilePtr);
	if(unCount != stWaveFileHeader.ulDataSize)
	{
		DEBUG_OUTPUT("Count does not equal wave header data size");
		return false;
	}

	nError = fclose(pFilePtr);
	if(nError != 0)
	{
		DEBUG_OUTPUT("Closing the file pointer produced an error");
		return false;
	}

	hResult = (*pSecondaryBuffer)->Lock(0, stWaveFileHeader.ulDataSize, (void**)&pBufferPtr, (DWORD*)&unBufferSize, NULL, 0, 0);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to lock secondary buffer");
		return false;
	}

	memcpy(pBufferPtr, pWaveData, stWaveFileHeader.ulDataSize);

	hResult = (*pSecondaryBuffer)->Unlock((void*)pBufferPtr, unBufferSize, NULL, 0);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to unlock secondary buffer");
		return false;
	}

	delete [] pWaveData;
	pWaveData = nullptr;

	return true;
}

void CSoundClass::ShutDownWaveFile(IDirectSoundBuffer8** pSecondaryBuffer)
{
	if(*pSecondaryBuffer)
	{
		(*pSecondaryBuffer)->Release();
		*pSecondaryBuffer = nullptr;
	}
}

bool CSoundClass::PlayWaveFile()
{
	HRESULT hResult;

	hResult = m_pSecondaryBuffer->SetCurrentPosition(0);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to set the secondary buffer current position");
		return false;
	}

	hResult = m_pSecondaryBuffer->SetVolume(DSBVOLUME_MAX);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to set the secondary buffer volume");
		return false;
	}

	hResult = m_pSecondaryBuffer->Play(0, 0, 0);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to play secondary buffer");
		return false;
	}

	return true;
}